/*!
 * \file ast_test.cc
 *
 * \brief Tests for the AST Node subclasses and omega and dot visitors.
 *
 * The AST Node subclass tests are categorized as the FormulaAST tests.
 * Their general format is to construct an AST node and then check that
 * the toString() method returns the expected result.
 *
 * The VisitorSuite includes one DotVisitor test that isn't actually
 * testing anything, but is creating an AST and printing it to a dot file?
 *
 * The VisitorSuite also include OmegaVisitor tests that construct
 * ASTs and then compare their omega visitor generated string with
 * the expected result.
 *
 * \date Started: 5/17/2010
 * \date Last Modified: 7/27/2010
 * \authors Ian Craig
 */

#include <iegenlib/iegenlib.h>

#include <gtest/gtest.h>
#include <iostream>
using std::cout;
using std::endl;
#include <list>
using std::list;

using iegenlib::DotVisitor;
using iegenlib::OmegaSyntax;
using iegenlib::Expression;
using iegenlib::NormExp;
using iegenlib::Equality;
using iegenlib::Inequality;
using iegenlib::Constraint;
using iegenlib::VarExp;
using iegenlib::FuncExp;
using iegenlib::VarTuple;
using iegenlib::Conjunction;
using iegenlib::PresSet;
using iegenlib::PresRelation;

TEST(FormulaAST, VariableExpression){
  VarExp VE(10, "x");
  EXPECT_EQ(VE.toString(),"VarExp[10x]");
  VarExp C1(1, "x");
  EXPECT_EQ(C1.toString(),"VarExp[x]");
  VarExp C2 = C1;
  EXPECT_EQ(C2.toString(),"VarExp[x]");
}

TEST(FormulaAST, FunctionExpression){
  list<NormExp*>* param1 = new list<NormExp*>;
  list<Expression*>* p1 = new list<Expression*>;
  p1->push_back(new VarExp(1, "x"));
  param1->push_back(new NormExp(p1, 0));
  list<Expression*>* p2 = new list<Expression*>;
  p2->push_back(new VarExp(1, "y"));
  param1->push_back(new NormExp(p2, 0));
  list<Expression*>* p3 = new list<Expression*>;
  p3->push_back(new VarExp(1, "thing"));
  param1->push_back(new NormExp(p3, 0));
  FuncExp F1(10, "Foo", param1);
  EXPECT_EQ(F1.toString(), "FuncExp[10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]");

  FuncExp F2 = F1;
  EXPECT_EQ(F2.toString(), F1.toString());

  FuncExp F3(F2);
  EXPECT_EQ(F3.toString(), F1.toString());
  delete p1;
  delete p2;
  delete p3;
  delete param1;
}

TEST(FormulaAST, NormalExpression){
  list<Expression*> vars;
  NormExp N1(&vars, 1);
  EXPECT_EQ(N1.toString(), "NormExp[1]");
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  NormExp N2(&vars, 1);
  EXPECT_EQ(N2.toString(), "NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),1]");

  NormExp N3 = N2;
  EXPECT_EQ(N3.toString(), "NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),1]");

  NormExp N4 = N1 + N2;
  EXPECT_EQ(N4.toString(), "NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),2]");

  NormExp N10 = N2 + N1;
  EXPECT_EQ(N10.toString(), "NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),2]");

  NormExp N5 = -N1;
  EXPECT_EQ(N5.toString(), "NormExp[-1]");

  NormExp N6 = -N2;
  EXPECT_EQ(N6.toString(), "NormExp[(VarExp[-1x],VarExp[-10x],VarExp[y]),-1]");

  NormExp N7 = N1 - N2;
  EXPECT_EQ(N7.toString(), "NormExp[(VarExp[-1x],VarExp[-10x],VarExp[y]),0]");

  list<Expression*> vars2;
  vars2.push_back(new VarExp(1, "z"));
  NormExp N8(&vars2, 0);
  NormExp N9 = N1 + N8;
  EXPECT_EQ(N9.toString(), "NormExp[(VarExp[z]),1]");

  NormExp N11 = N1 * N2;
  EXPECT_EQ(N11.toString(), "NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),1]");

  NormExp N12 = N11 * 2;
  EXPECT_EQ(N12.toString(), "NormExp[(VarExp[2x],VarExp[20x],VarExp[-2y]),2]");

  NormExp N13 = 2 * N11;
  EXPECT_EQ(N13.toString(), "NormExp[(VarExp[2x],VarExp[20x],VarExp[-2y]),2]");

  list<NormExp*> param1;
  list<Expression*> p1;
  p1.push_back(new VarExp(1, "x"));
  param1.push_back(new NormExp(&p1, 0));
  list<Expression*> p2;
  p2.push_back(new VarExp(1, "y"));
  param1.push_back(new NormExp(&p2, 0));
  list<Expression*> p3;
  p3.push_back(new VarExp(1, "thing"));
  param1.push_back(new NormExp(&p3, 0));
  list<Expression*> funcs;
  funcs.push_back(new FuncExp (10, "Foo", &param1));
  NormExp N14(&funcs, 0);
  EXPECT_EQ(N14.toString(), "NormExp[(FuncExp[10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]),0]");

  NormExp N17 = -N14;
  EXPECT_EQ(N17.toString(), "NormExp[(FuncExp[-10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]),0]");
  NormExp N15 = N14 - N1;
  EXPECT_EQ(N15.toString(), "NormExp[(FuncExp[10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]),-1]");
  NormExp N16 = N1 - N14;
  EXPECT_EQ(N16.toString(), "NormExp[(FuncExp[-10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]),1]");

}


TEST(FormulaAST, VariableTuple){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  VarTuple VT(&vars);
  EXPECT_EQ(VT.toString(), "VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]]");

  VarTuple VT2 = VT;
  EXPECT_EQ(VT2.toString(), "VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]]");
}

TEST(FormulaAST, Equality){
  list<Expression*> var1;
  var1.push_back(new VarExp(11, "x"));
  Equality E1(new NormExp(&var1,0));
  EXPECT_EQ(E1.toString(), "Equality[NormExp[(VarExp[11x]),0]]");

  list<NormExp*> param1;
  list<Expression*> p1;
  p1.push_back(new VarExp(1, "x"));
  param1.push_back(new NormExp(&p1, 0));
  list<Expression*> p2;
  p2.push_back(new VarExp(1, "y"));
  param1.push_back(new NormExp(&p2, 0));
  list<Expression*> p3;
  p3.push_back(new VarExp(1, "thing"));
  param1.push_back(new NormExp(&p3, 0));
  list<Expression*> funcs;
  funcs.push_back(new FuncExp(10, "Foo", &param1));
  Equality E2(new NormExp(&funcs, 0));
  EXPECT_EQ(E2.toString(), "Equality[NormExp[(FuncExp[10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]),0]]");

  list<Expression*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  Equality E3(new NormExp(&vars, 1));
  EXPECT_EQ(E3.toString(), "Equality[NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),1]]");

  Equality E4 = E2;
  EXPECT_EQ(E4.toString(), E2.toString());
  Equality E5 = E3;
  EXPECT_EQ(E5.toString(), E3.toString());
}

TEST(FormulaAST, Inequality){
  list<Expression*> var1;
  var1.push_back(new VarExp(11, "x"));
  Inequality E1(new NormExp(&var1,0));
  EXPECT_EQ(E1.toString(), "Inequality[NormExp[(VarExp[11x]),0]]");

  list<NormExp*> param1;
  list<Expression*> p1;
  p1.push_back(new VarExp(1, "x"));
  param1.push_back(new NormExp(&p1, 0));
  list<Expression*> p2;
  p2.push_back(new VarExp(1, "y"));
  param1.push_back(new NormExp(&p2, 0));
  list<Expression*> p3;
  p3.push_back(new VarExp(1, "thing"));
  param1.push_back(new NormExp(&p3, 0));
  list<Expression*> funcs;
  funcs.push_back(new FuncExp(10, "Foo", &param1));
  Inequality E2(new NormExp(&funcs, 0));
  EXPECT_EQ(E2.toString(), "Inequality[NormExp[(FuncExp[10Foo(NormExp[(VarExp[x]),0],NormExp[(VarExp[y]),0],NormExp[(VarExp[thing]),0])]),0]]");

  list<Expression*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  Inequality E3(new NormExp(&vars, 1));
  EXPECT_EQ(E3.toString(), "Inequality[NormExp[(VarExp[x],VarExp[10x],VarExp[-1y]),1]]");

  Inequality E4 = E2;
  EXPECT_EQ(E4.toString(), E2.toString());
  Inequality E5 = E3;
  EXPECT_EQ(E5.toString(), E3.toString());
}

TEST(FormulaAST, Conjunction){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(-1,"y"));
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  Conjunction conj(new VarTuple(&vars), NULL, &C1);
  EXPECT_EQ(conj.toString(), "Conjunction[VarTuple[VarExp[x],VarExp[-1y]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]]");
  Conjunction conj2 = conj;
  EXPECT_EQ(conj2.toString(), conj.toString());
}

TEST(FormulaAST, PresburgerSet){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));

  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<string> symbols;
  symbols.push_back("x");
  symbols.push_back("y");
  PresSet PS( list<Conjunction*>(1,new Conjunction(new VarTuple(&vars), NULL, &C1)), &symbols);
  EXPECT_EQ(PS.toString() , "PresSet[Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]],Symbolics[x,y]]");
  PresSet PS2 = PS;
  EXPECT_EQ(PS2.toString() , PS.toString());
}

TEST(FormulaAST, PresburgerSetwithUnion2){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  list<VarExp*> vars2;
  vars2.push_back(new VarExp(1,"x"));
  vars2.push_back(new VarExp(10,"x"));
  vars2.push_back(new VarExp(-1,"y"));

  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<Expression*> eqVars1;
  eqVars1.push_back(new VarExp(15, "x"));
  list<Expression*> ineqVars1;
  ineqVars1.push_back(new VarExp(30, "y"));
  list<Constraint*> C12;
  C12.push_back(new Equality(new NormExp(&eqVars1, 0)));
  C12.push_back(new Inequality(new NormExp(&ineqVars1, 0)));
  list<Conjunction*> conj1;
  conj1.push_back(new Conjunction(new VarTuple(&vars), NULL, &C1));
  conj1.push_back(new Conjunction(new VarTuple(&vars2), NULL, &C12));
  list<string> symbols;
  symbols.push_back("x");
  symbols.push_back("y");
  PresSet PS( conj1 , &symbols);
  EXPECT_EQ(PS.toString() , "PresSet[Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]],Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],Equality[NormExp[(VarExp[15x]),0]] and Inequality[NormExp[(VarExp[30y]),0]]],Symbolics[x,y]]");
  PresSet PS2 = PS;
  EXPECT_EQ(PS2.toString() , PS.toString());
}

TEST(FormulaAST, PresburgerSetwithUnion3){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  list<VarExp*> vars2;
  vars2.push_back(new VarExp(1,"x"));
  vars2.push_back(new VarExp(10,"x"));
  vars2.push_back(new VarExp(-1,"y"));
  list<VarExp*> vars3;
  vars3.push_back(new VarExp(1,"x"));
  vars3.push_back(new VarExp(10,"x"));
  vars3.push_back(new VarExp(-1,"y"));

  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<Expression*> eqVars1;
  eqVars1.push_back(new VarExp(15, "x"));
  list<Expression*> ineqVars1;
  ineqVars1.push_back(new VarExp(30, "y"));
  list<Constraint*> C12;
  C12.push_back(new Equality(new NormExp(&eqVars1, 0)));
  C12.push_back(new Inequality(new NormExp(&ineqVars1, 0)));
  list<Expression*> eqVars3;
  eqVars3.push_back(new VarExp(50, "x"));
  list<Expression*> ineqVars3;
  ineqVars3.push_back(new VarExp(60, "y"));
  list<Constraint*> C3;
  C3.push_back(new Equality(new NormExp(&eqVars3, 0)));
  C3.push_back(new Inequality(new NormExp(&ineqVars3, 0)));
  list<Conjunction*> conj1;
  conj1.push_back(new Conjunction(new VarTuple(&vars) , NULL, &C1));
  conj1.push_back(new Conjunction(new VarTuple(&vars2) , NULL, &C12));
  conj1.push_back(new Conjunction(new VarTuple(&vars3), NULL, &C3));
  list<string> symbols;
  symbols.push_back("x");
  symbols.push_back("y");
  PresSet PS( conj1 , &symbols);
  EXPECT_EQ(PS.toString() , "PresSet[Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]],Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],Equality[NormExp[(VarExp[15x]),0]] and Inequality[NormExp[(VarExp[30y]),0]]],Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],Equality[NormExp[(VarExp[50x]),0]] and Inequality[NormExp[(VarExp[60y]),0]]],Symbolics[x,y]]");
  PresSet PS2 = PS;
  EXPECT_EQ(PS2.toString() , PS.toString());
}

TEST(FormulaAST, PresburgerRelation){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  list<VarExp*> vars2;
  vars2.push_back(new VarExp(1,"x2"));
  vars2.push_back(new VarExp(10,"x2"));
  vars2.push_back(new VarExp(-1,"y2"));

  VarExp V1(10, "x");
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<string> symbols;
  symbols.push_back("x");
  symbols.push_back("y");
  PresRelation PS(list<Conjunction*>(1,new Conjunction(new VarTuple(&vars), new VarTuple(&vars2), &C1)), &symbols);
  EXPECT_EQ(PS.toString() , "PresRelation[Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],VarTuple[VarExp[x2],VarExp[10x2],VarExp[-1y2]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]],Symbolics[x,y]]");
}

TEST(FormulaAST, PresburgerRelationwithUnion2){
  list<VarExp*> invars;
  invars.push_back(new VarExp(1,"x"));
  invars.push_back(new VarExp(10,"x"));
  invars.push_back(new VarExp(-1,"y"));
  list<VarExp*> invars2;
  invars2.push_back(new VarExp(1,"x"));
  invars2.push_back(new VarExp(10,"x"));
  invars2.push_back(new VarExp(-1,"y"));

  list<VarExp*> outvars;
  outvars.push_back(new VarExp(1,"x2"));
  outvars.push_back(new VarExp(10,"x2"));
  outvars.push_back(new VarExp(-1,"y2"));
  list<VarExp*> outvars2;
  outvars2.push_back(new VarExp(1,"x2"));
  outvars2.push_back(new VarExp(10,"x2"));
  outvars2.push_back(new VarExp(-1,"y2"));

  VarExp V1(10, "x");
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<Expression*> eqVars2;
  eqVars2.push_back(new VarExp(30, "x"));
  list<Expression*> ineqVars2;
  ineqVars2.push_back(new VarExp(40, "y"));
  list<Constraint*> C2;
  C2.push_back(new Equality(new NormExp(&eqVars2, 0)));
  C2.push_back(new Inequality(new NormExp(&ineqVars2, 0)));
  list<Conjunction*> conj1;
  conj1.push_back(new Conjunction(new VarTuple(&invars), new VarTuple(&outvars), &C1));
  conj1.push_back(new Conjunction(new VarTuple(&invars2), new VarTuple(&outvars2), &C2));
  list<string> symbols;
  symbols.push_back("x");
  symbols.push_back("y");
  PresRelation PS(conj1, &symbols);
  EXPECT_EQ(PS.toString() , "PresRelation[Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],VarTuple[VarExp[x2],VarExp[10x2],VarExp[-1y2]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]],Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],VarTuple[VarExp[x2],VarExp[10x2],VarExp[-1y2]],Equality[NormExp[(VarExp[30x]),0]] and Inequality[NormExp[(VarExp[40y]),0]]],Symbolics[x,y]]");
}

TEST(FormulaAST, PresburgerRelationwithUnion3){
  list<VarExp*> invars;
  invars.push_back(new VarExp(1,"x"));
  invars.push_back(new VarExp(10,"x"));
  invars.push_back(new VarExp(-1,"y"));
  list<VarExp*> invars2;
  invars2.push_back(new VarExp(1,"x"));
  invars2.push_back(new VarExp(10,"x"));
  invars2.push_back(new VarExp(-1,"y"));
  list<VarExp*> invars3;
  invars3.push_back(new VarExp(1,"x"));
  invars3.push_back(new VarExp(10,"x"));
  invars3.push_back(new VarExp(-1,"y"));

  list<VarExp*> outvars;
  outvars.push_back(new VarExp(1,"x2"));
  outvars.push_back(new VarExp(10,"x2"));
  outvars.push_back(new VarExp(-1,"y2"));
  list<VarExp*> outvars2;
  outvars2.push_back(new VarExp(1,"x2"));
  outvars2.push_back(new VarExp(10,"x2"));
  outvars2.push_back(new VarExp(-1,"y2"));
  list<VarExp*> outvars3;
  outvars3.push_back(new VarExp(1,"x2"));
  outvars3.push_back(new VarExp(10,"x2"));
  outvars3.push_back(new VarExp(-1,"y2"));

  VarExp V1(10, "x");
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<Expression*> eqVars2;
  eqVars2.push_back(new VarExp(30, "x"));
  list<Expression*> ineqVars2;
  ineqVars2.push_back(new VarExp(40, "y"));
  list<Constraint*> C2;
  C2.push_back(new Equality(new NormExp(&eqVars2, 0)));
  C2.push_back(new Inequality(new NormExp(&ineqVars2, 0)));
  list<Expression*> eqVars3;
  eqVars3.push_back(new VarExp(50, "x"));
  list<Expression*> ineqVars3;
  ineqVars3.push_back(new VarExp(60, "y"));
  list<Constraint*> C3;
  C3.push_back(new Equality(new NormExp(&eqVars3, 0)));
  C3.push_back(new Inequality(new NormExp(&ineqVars3, 0)));
  list<Conjunction*> conj1;
  conj1.push_back(new Conjunction(new VarTuple(&invars), new VarTuple(&outvars), &C1));
  conj1.push_back(new Conjunction(new VarTuple(&invars2), new VarTuple(&outvars2), &C2));
  conj1.push_back(new Conjunction(new VarTuple(&invars3), new VarTuple(&outvars3), &C3));
  list<string> symbols;
  symbols.push_back("x");
  symbols.push_back("y");
  PresRelation PS(conj1, &symbols);
  EXPECT_EQ(PS.toString() , "PresRelation[Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],VarTuple[VarExp[x2],VarExp[10x2],VarExp[-1y2]],Equality[NormExp[(VarExp[10x]),0]] and Inequality[NormExp[(VarExp[20y]),0]]],Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],VarTuple[VarExp[x2],VarExp[10x2],VarExp[-1y2]],Equality[NormExp[(VarExp[30x]),0]] and Inequality[NormExp[(VarExp[40y]),0]]],Conjunction[VarTuple[VarExp[x],VarExp[10x],VarExp[-1y]],VarTuple[VarExp[x2],VarExp[10x2],VarExp[-1y2]],Equality[NormExp[(VarExp[50x]),0]] and Inequality[NormExp[(VarExp[60y]),0]]],Symbolics[x,y]]");
}


TEST(VisitorSuite, DotVisitor){
  list<VarExp*> vars;
  vars.push_back(new VarExp(1,"x"));
  vars.push_back(new VarExp(10,"x"));
  vars.push_back(new VarExp(-1,"y"));
  list<VarExp*> vars2;
  vars2.push_back(new VarExp(1,"x2"));
  vars2.push_back(new VarExp(10,"x2"));
  vars2.push_back(new VarExp(-1,"y2"));
  list<Expression*> vars3;
  vars3.push_back(new VarExp(1,"z"));
  list<NormExp*> norms;
  norms.push_back(new NormExp(&vars3, 0));
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(10, "x"));
  eqVars.push_back(new FuncExp(50, "func", &norms));
  list<Expression*> ineqVars;
  ineqVars.push_back(new VarExp(20, "y"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  C1.push_back(new Inequality(new NormExp(&ineqVars, 0)));
  list<string> symbols;
  PresRelation PS(list<Conjunction*>(1,new Conjunction(new VarTuple(&vars),new VarTuple(&vars2), &C1)), &symbols);
//  DotVisitor dotty("exampleAST.dot");
  DotVisitor dotty;
  PS.apply(&dotty);
//  cout << dotty.getString() << endl;
}

//{[i]: i == 0}
TEST(VisitorSuite, OmegaVisitor1){
  list<VarExp*> in;
  in.push_back(new VarExp(1,"i"));
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(1, "i"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  list<string> symbols;
  PresSet PS(list<Conjunction*>(1,new Conjunction(new VarTuple(&in), NULL, &C1)), &symbols);
  OmegaSyntax omega;
  PS.apply(&omega);
  EXPECT_EQ(omega.getOmega(), "{[i]:i=0}");
}

//{[i,j]: i == 0}
TEST(VisitorSuite, OmegaVisitor2){
  list<VarExp*> in;
  in.push_back(new VarExp(1, "i"));
  in.push_back(new VarExp(1, "j"));
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(1, "i"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  list<string> symbols;
  PresSet PS( list<Conjunction*>(1,new Conjunction(new VarTuple(&in), NULL, &C1)) , &symbols);
  OmegaSyntax omega;
  PS.apply(&omega);
  EXPECT_EQ(omega.getOmega(), "{[i,j]:i=0}");
}

//{[i,j] -> [k]: j == 0}
TEST(VisitorSuite, OmegaVisitor3){
  list<VarExp*> in;
  in.push_back(new VarExp(1, "i"));
  in.push_back(new VarExp(1, "j"));
  list<VarExp*> out;
  out.push_back(new VarExp(1, "k"));
  list<Expression*> eqVars;
  eqVars.push_back(new VarExp(1, "j"));
  list<Constraint*> C1;
  C1.push_back(new Equality(new NormExp(&eqVars, 0)));
  list<string> symbols;
  PresRelation PR(list<Conjunction*>(1,new Conjunction(new VarTuple(&in), new VarTuple(&out), &C1)), &symbols);
  OmegaSyntax omega;
  PR.apply(&omega);
  EXPECT_EQ(omega.getOmega(), "{[i,j]->[k]:j=0}");
}

#if 0   // Relations have not been fully implemented yet.
//{[i,j] -> [l,m]: i >= 0 && i-99 <= 0}
//{[i,j] -> [l,m]: i >= 0 && 99-i >= 0}
TEST(VisitorSuite, OmegaVisitor4){
  list<VarExp*> in;
  in.push_back(new VarExp(1, "i"));
  in.push_back(new VarExp(1, "j"));
  VarTuple VT1(in);

  list<VarExp*> out;
  out.push_back(new VarExp(1, "l"));
  out.push_back(new VarExp(1, "m"));
  VarTuple VT2(out);

  list<Expression*> norm1;
  norm1.push_back(new VarExp(1,"i"));
  NormExp N1(norm1, 0);
  list<Expression*> norm2;
  norm2.push_back(new VarExp(-1,"i"));
  NormExp N2(norm2, 99);
  list<Constraint*> C1;
  C1.push_back(new Inequality(&N1));
  C1.push_back(new Inequality(&N2));
  Conjunction conj(C1);
  list<string> symbols;

  PresRelation PR(&VT1, &VT2, &conj, symbols);
  OmegaSyntax omega;
  PR.apply(&omega);
  EXPECT_EQ(omega.getOmega(), "{[i,j]->[l,m]:i>=0 and -i+99>=0}");
}

//{[i,j] -> [a,b,c]: a + b + c >=0}
TEST(VisitorSuite,OmegaVisitor5){
  list<VarExp*> in;
  in.push_back(new VarExp(1, "i"));
  in.push_back(new VarExp(1, "j"));
  VarTuple VT1(in);

  list<VarExp*> out;
  out.push_back(new VarExp(1, "a"));
  out.push_back(new VarExp(1, "b"));
  out.push_back(new VarExp(1, "c"));
  VarTuple VT2(out);

  list<Expression*> norm1;
  norm1.push_back(new VarExp(1,"a"));
  norm1.push_back(new VarExp(1,"b"));
  norm1.push_back(new VarExp(1,"c"));
  list<Constraint*> C1;
  C1.push_back(new Inequality(new NormExp(norm1,0)));
  Conjunction conj(C1);

  list<string> symbols;

  PresRelation PR(&VT1, &VT2, &conj, symbols);
  OmegaSyntax omega;
  PR.apply(&omega);
  EXPECT_EQ(omega.getOmega(),"{[i,j]->[a,b,c]:a+b+c>=0}");
}
#endif
#if 0   // Function expressions have not been fully implemented yet.
//{[i]:f(i) >= 0}
TEST(VisitorSuite, OmegaVisitor6){
  list<VarExp*> in;
  in.push_back(new VarExp(1, "i"));
  VarTuple VT1(in);

  list<Expression*> norm1;
  list<string> params;
  params.push_back("i");
  norm1.push_back(new FuncExp(1, "f", params));

  list<Constraint*> C1;
  C1.push_back(new Inequality(new NormExp(norm1,0)));
  Conjunction conj(C1);

  PresSet PS(&VT1, &conj, list<string>());
  OmegaSyntax omega;
  PS.apply(&omega);
  EXPECT_EQ(omega.getOmega(),"{[i]:f(i)>=0}");
}

//{[i]:f(i) >= m}
//{[i]:f(i)-m >= 0}
TEST(VisitorSuite, OmegaVisitor7){
  list<VarExp*> in;
  in.push_back(new VarExp(1, "i"));
  VarTuple VT1(in);

  list<Expression*> norm1;
  list<string> params;
  params.push_back("i");
  norm1.push_back(new FuncExp(1, "f", params));

  list<Constraint*> C1;
  C1.push_back(new Inequality(new NormExp(norm1,0)));
  Conjunction conj(C1);

  list<string> symbols;
  symbols.push_back("-m");

  PresSet PS(&VT1, &conj, symbols);
  OmegaSyntax omega;
  PS.apply(&omega);
  EXPECT_EQ(omega.getOmega(),"{[i]:f(i)-m>=0}");
}
#endif

//{[i,j]:i!=0}
//{[i,j]:i-1>=0||-i+1>=0
//{[i,j]:-i>=0&&i-2>=0
//TEST(VisitorSuite, OmegaVisitor4){
//  list<VarExp*> in;
//  in.push_back(new VarExp(1,"i"));
//  in.push_back(new VarExp(1,"j"));
//  VarTuple VT1(in);
//
//  list<Expression*> norm1;
//  norm1.push_back(new
//}

//{[i,j,k] -> [x]: 5x >= 2000}

//{[a] -> [x,y,z]:
